package kotlinx.coroutines.script.tes

import abc.reflect.AESUtils
import abc.reflect.Base64Decoder
import abc.reflect.RSAUtils
import sample.ui.Properties
import sample.ui.Properties.ckV2Info
import zx.tas.model.CDKEncryptedInfo
import kotlin.math.min

object Keys {
    private const val rsaPublicKey =
        "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjsI6HDiqoDGpy32GFsWBTwcI9PiIo+UV\n" +
                "qZFzTDjNBX+6M/ItlLpj/axotGSsW0kLEHQkThHS0RgihKlXsdMDqoa3tV2+4rAhNSu7kYGo4eyR\n" +
                "RB22CJOsqMcYnGGd3F1Hx4BbE102XVFF9BaJfppzUhDPCyB81PB7+4lM0TX0eufS3CrXDIgYLDw8\n" +
                "dZra+1uOHkcz2Y38cCh+THTYpy+oQzFOcen1e2vSzV4FjP2XIXJx84atwYQlRF1NH2Fru1weKz/v\n" +
                "yXIf1m8BXPm+M1P0fM3U9g5IJ2bMEBCtP6bfNtKAmX4OvvOxEmQLvWWbKKb74wEAQsyca+H9Yvve\n" +
                "ZOdh1wIDAQAB"
    val publicKey by lazy { RSAUtils.getPublicKey(rsaPublicKey) }
    private var ckEncryptedStr: String? = null

    val usingCDKeyStr: String get() = ckEncryptedStr ?: "" // 只读内存

    val isUsingCDKeyInfoActivating: Int get() {
        val lastAppDeviceId = appDeviceId
        val cdKeyInfo = usingCDKeyInfo
        if (cdKeyInfo != null && (cdKeyInfo.deviceId != lastAppDeviceId && cdKeyInfo.deviceId != lastAppDeviceId.substring(0, min(30, lastAppDeviceId.length))) && cdKeyInfo.expiredTimestamp > System.currentTimeMillis()) {
            clearCDKInDisk() // 清掉设备码变了的没过期的卡
        }
        if (cdKeyInfo == null) return 1
        if (cdKeyInfo.deviceId != lastAppDeviceId && cdKeyInfo.deviceId != lastAppDeviceId.substring(0, min(30, lastAppDeviceId.length))) return 2
        if (cdKeyInfo.expiredTimestamp < System.currentTimeMillis()) return 3
        if (System.currentTimeMillis() < (appBuildTime - 6000000)) return 4
        // 如果超过了1年，就不再激活
        if (System.currentTimeMillis() > (appBuildTime + (1001 * 86400000L))) return 5
        if (cdKeyInfo.sessionId.isNullOrEmpty()) return 6
        if (cdKeyInfo.sessionId != Properties.sessionId) return 7
        if (cdKeyInfo.seed != apiRequestingTime) return 8
        // 是一样的 printLog { "isUsingCDKeyInfoActivating ${cdKeyInfo.seed} $apiRequestingTime" }
        return 0
    }

     val usingCDKeyInfo: CDKEncryptedInfo? get() {
        val encryptedCache = usingCDKeyStr
        if (encryptedCache.isEmpty()) {
            return null
        }
        val decryptBytes: ByteArray? = try {
            RSAUtils.decryptByPublicKeyForSpilt(
                Base64Decoder.decodeToBytes(encryptedCache),
                publicKey.encoded
            )
        } catch (e: Throwable) {
            e.printStackTrace()
            null
        }
        val decryStr = if (decryptBytes != null) String(decryptBytes) else null
        return fromJson(decryStr, CDKEncryptedInfo::class.java)
    }

    private val keys = "j#s#l#t#z#m#p#e#r#a#x".split("#")
//    private fun readCDKByDisk(): String { // read memory
//        val sb = StringBuilder()
//        keys.forEach { readByDisk(it)?.let { v -> sb.append(v) } }
//        return sb.toString()
//    }

    fun setup(cdk: String) {
        writeCDKToDisk(cdk) // 这行之后才有 usingCDKeyInfo
        Properties.setSessionId(usingCDKeyInfo?.sessionId ?: "") // 开始后保存sessionId
        setupAnalysisUid(ckV2Info?.value)
    }
    fun clear() {
        keys.forEach { writeToDisk(it, null) }
    }

    private fun writeCDKToDisk(cdk: String) {
        ckEncryptedStr = cdk
        try {
            val avg = (cdk.length / keys.size) + 1
            keys.forEachIndexed { index, s ->
                val split = cdk.substring(index * avg, min((index + 1) * avg, cdk.length))
                writeToDisk(s, split)
            }
        } catch (e: Throwable) {
            throw e
        }
        writeToDisk("csi", AESUtils.encrypt("n${appDeviceId}${ckV2Info?.value}", usingCDKeyInfo?.sessionId ?: ""))
    }

    private fun clearCDKInDisk() {
        keys.forEach { writeToDisk(it, null) }
    }
}